package com.zhengqing.demo.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.zhengqing.demo.model.dto.HpvDTO;
import com.zhengqing.demo.model.dto.MbglmzDTO;
import com.zhengqing.demo.model.dto.MbglzyDTO;
import com.zhengqing.demo.model.dto.MzrzDTO;
import com.zhengqing.demo.model.dto.RxccDTO;
import com.zhengqing.demo.model.dto.RxmbDTO;
import com.zhengqing.demo.model.dto.RxssDTO;
import com.zhengqing.demo.model.dto.TctDTO;
import com.zhengqing.demo.model.dto.ZyrzDTO;
import com.zhengqing.demo.model.vo.ApiRespVO;
import com.zhengqing.demo.service.IEasyExcelReadService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


/**
 * @author new
 * 业务服务实现类
 */
@Slf4j
@Service
public class EasyExcelReadServiceImpl implements IEasyExcelReadService {

    @Value("${write.doc.path}")
    private String writeRootDirectory;

    /**
     * 分类小写
     */
    private static final List<String> CATEGORIES = Arrays.asList(
            "BI-RADS 1类",
            "BI-RADS 2类",
            "BI-RADS 3类",
            "BI-RADS 4类",
            "BI-RADS 4a类",
            "BI-RADS 4b类",
            "BI-RADS 4c类",
            "BI-RADS 5类",
            "BI-RADS 6类",
            "BI-RADS 0类");


    private static final List<String> CATEGORIES_FOUR = Arrays.asList(
            "BI-RADS 4a类",
            "BI-RADS 4b类",
            "BI-RADS 4c类");

    @PostConstruct
    private void init() throws IOException {
        Path path = Paths.get(writeRootDirectory);
        if (!Files.exists(path)) {
            Files.createDirectories(path);
        }
    }

    @Override
    @SneakyThrows(Exception.class)
    public ApiRespVO rxccReadAndExport(MultipartFile file) {
        List<RxccDTO> rxccList = new ArrayList<>();
        EasyExcel.read(file.getInputStream(), RxccDTO.class, new ReadListener<RxccDTO>() {

            public static final int BATCH_COUNT = 100;
            private List<RxccDTO> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

            @Override
            public void invoke(RxccDTO data, AnalysisContext context) {
                this.cachedDataList.add(data);
                if (this.cachedDataList.size() >= BATCH_COUNT) {
                    // 处理业务逻辑
                    this.handleData();
                    // 存储完成清理 list
                    this.cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                }
            }

            private void handleData() {
                if (CollUtil.isEmpty(this.cachedDataList)) {
                    return;
                }
                log.info("本批次共{}条数据，开始过滤！", this.cachedDataList.size());
                List<RxccDTO> filteredList = this.cachedDataList
                        .stream()
                        .filter(i -> "女".equals(i.getSex()) && !"0".equals(i.getChargeMoney()))
                        .collect(Collectors.toList());
                log.info("过滤后还剩{}条数据！", filteredList.size());

                for (RxccDTO item : filteredList) {
                    String checkConclusion = item.getCheckConclusion();
                    if (StrUtil.isBlank(checkConclusion)) {
                        rxccList.add(item);
                        continue;
                    }
                    Optional<String> foundUpperCate = CATEGORIES
                            .stream()
                            .filter(checkConclusion::contains)
                            .reduce((first, second) -> second);
                    List<String> lowerCates = CATEGORIES
                            .stream()
                            .map(String::toLowerCase)
                            .collect(Collectors.toList());
                    Optional<String> foundLowerCate = lowerCates
                            .stream()
                            .filter(checkConclusion::contains)
                            .reduce((first, second) -> second);

                    String filteredCate = foundUpperCate.orElse(foundLowerCate.orElse(checkConclusion));
                    if (StrUtil.isNotBlank(filteredCate)) {
                        if (CATEGORIES_FOUR.stream().anyMatch(filteredCate::contains)) {
                            filteredCate = "4类";
                        } else {
                            filteredCate = filteredCate.replaceAll("BI-RADS ", "");
                        }
                    }
                    RxccDTO rxccDTO = new RxccDTO();
                    BeanUtil.copyProperties(item, rxccDTO);
//                    rxccDTO.setCategory(filteredCate);
                    rxccDTO.setCheckConclusionCategory(findMaxBIRADS(checkConclusion));
                    rxccList.add(rxccDTO);
                }
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                this.handleData();
                log.info("共处理了{}条数据！接下析来开始导出", rxccList.size());
                // 导出
                String fileName = writeRootDirectory + FileUtil.getPrefix(file.getOriginalFilename()) + "(处理后).xlsx";
                EasyExcel.write(new File(fileName), RxccDTO.class).sheet("Sheet1").doWrite(rxccList);
                log.info("导出完成！");
            }
        }).sheet().headRowNumber(1).doRead();
        String path = "文件生成路径：" + writeRootDirectory + FileUtil.getPrefix(file.getOriginalFilename()) + "(处理后).xlsx";
        return new ApiRespVO("200", Collections.singletonList(path));
    }

    @Override
    @SneakyThrows(Exception.class)
    public ApiRespVO rxmbReadAndExport(MultipartFile file) {
        List<RxmbDTO> rxmbList = new ArrayList<>();
        EasyExcel.read(file.getInputStream(), RxmbDTO.class, new ReadListener<RxmbDTO>() {
            public static final int BATCH_COUNT = 100;
            private List<RxmbDTO> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

            @Override
            public void invoke(RxmbDTO data, AnalysisContext context) {
                this.cachedDataList.add(data);
                if (this.cachedDataList.size() >= BATCH_COUNT) {
                    this.handleData();
                    this.cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                }
            }

            private void handleData() {
                if (CollUtil.isEmpty(this.cachedDataList)) {
                    return;
                }
                log.info("本批次共{}条数据，开始过滤！", this.cachedDataList.size());
                List<RxmbDTO> filteredList = this.cachedDataList
                        .stream()
                        .filter(i ->
                                ((StrUtil.isNotBlank(i.getSex()) && "女".equals(i.getSex()))
                                        || StrUtil.isBlank(i.getSex()))
                                        && !"0".equals(i.getChargeMoney())
                                        // 年龄再35 - 64之间
                                        && "35".compareTo(i.getAge()) <= 0 && "64".compareTo(i.getAge()) >= 0
                        )
                        .collect(Collectors.toList());
                log.info("过滤后还剩{}条数据！", filteredList.size());

                for (RxmbDTO item : filteredList) {
                    String checkConclusion = item.getCheckConclusion();
                    if (StrUtil.isBlank(checkConclusion)) {
                        rxmbList.add(item);
                        continue;
                    }
                    Optional<String> foundUpperCate = CATEGORIES
                            .stream()
                            .filter(checkConclusion::contains)
                            .reduce((first, second) -> second);
                    List<String> lowerCates = CATEGORIES
                            .stream()
                            .map(String::toLowerCase)
                            .collect(Collectors.toList());
                    Optional<String> foundLowerCate = lowerCates
                            .stream()
                            .filter(checkConclusion::contains)
                            .reduce((first, second) -> second);

                    String filteredCate = foundUpperCate.orElse(foundLowerCate.orElse(checkConclusion));
                    if (StrUtil.isNotBlank(filteredCate)) {
                        if (CATEGORIES_FOUR.stream().anyMatch(filteredCate::contains)) {
                            filteredCate = "4类";
                        } else {
                            filteredCate = filteredCate.replaceAll("BI-RADS ", "");
                        }
                    }
                    RxmbDTO rxmbDTO = new RxmbDTO();
                    BeanUtil.copyProperties(item, rxmbDTO);
//                    rxmbDTO.setCategory(filteredCate);
                    rxmbDTO.setCheckConclusionCategory(findMaxBIRADS(checkConclusion));
                    rxmbList.add(rxmbDTO);
                }
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                this.handleData();
                log.info("共处理了{}条数据！接下析来开始导出", rxmbList.size());
                // 导出
                String originalFilename = file.getOriginalFilename();
                String fileName = writeRootDirectory + FileUtil.getPrefix(originalFilename) + "(处理后).xlsx";
                EasyExcel.write(fileName, RxmbDTO.class).sheet("Sheet1").doWrite(rxmbList);
                log.info("导出完成！");
            }
        }).sheet().headRowNumber(1).doRead();
        String path = "文件生成路径：" + writeRootDirectory + FileUtil.getPrefix(file.getOriginalFilename()) + "(处理后).xlsx";
        return new ApiRespVO("200", Collections.singletonList(path));
    }

    public static void main(String[] args) {
        String text = "双侧乳腺低回声结节   BI-RADS 4类 \n" +
                "肝囊肿\n" +
                "甲状腺未见明显异常     C-TR 1类（分类依据C-TIRADS） \n" +
                "请结合临床\"";
        System.out.println(findMaxBIRADS(text));
    }

    private static String findMaxBIRADS(String text) {
        // 定义类别到优先级的映射
        Map<String, Integer> priorityMap = new HashMap<>(10);
        // 最高优先级
        priorityMap.put("0", 10);
        priorityMap.put("6", 9);
        priorityMap.put("5", 8);
        priorityMap.put("4", 7);
        priorityMap.put("4A", 6);
        priorityMap.put("4B", 5);
        priorityMap.put("4C", 4);
        priorityMap.put("3", 3);
        priorityMap.put("2", 2);
        priorityMap.put("1", 1);
        int leftBreast = 0;
        int rightBreast = 0;

        // 分割文本为单个描述项
        List<String> items = splitBySerialNumber(text);

        // 正则表达式匹配模式
        Pattern pattern = Pattern.compile("(双侧乳腺|左侧乳腺|右侧乳腺|双乳|左乳|右乳)(.*?)(?:BI-RADS\\s*([0-6]|4[a-c]))类", Pattern.CASE_INSENSITIVE);

        for (String item : items) {
            Matcher matcher = pattern.matcher(item);
            while (matcher.find()) {
                String side = matcher.group(1);
                String categoryStr = matcher.group(3).toUpperCase();
                // 默认值为0
                int priority = priorityMap.getOrDefault(categoryStr, 0);

                if ("双乳".equals(side) || "双侧乳腺".equals(side)) {
                    leftBreast = Math.max(leftBreast, priority);
                    rightBreast = Math.max(rightBreast, priority);
                } else if ("左乳".equals(side) || "左侧乳腺".equals(side)) {
                    leftBreast = Math.max(leftBreast, priority);
                } else if ("右乳".equals(side) || "右侧乳腺".equals(side)) {
                    rightBreast = Math.max(rightBreast, priority);
                }
            }
        }

        // 根据优先级确定最终结果
        int maxCategoryPriority = Math.max(leftBreast, rightBreast);
        if (maxCategoryPriority == 0) {
            return "未找到有效分类";
        } else {
            String resultSide = leftBreast == rightBreast ? "双乳" :
                    leftBreast > rightBreast ? "左乳" : "右乳";

            // 将优先级转换回原始类别表示
            for (Map.Entry<String, Integer> entry : priorityMap.entrySet()) {
                if (entry.getValue().equals(maxCategoryPriority)) {
                    return resultSide + (entry.getKey().startsWith("4") ? "4类" : entry.getKey() + "类");
                }
            }
        }
        return "未找到有效分类";
    }

    private static List<String> splitBySerialNumber(String text) {
        List<String> result = new ArrayList<>();
        String[] split = text.split("；");
        Arrays.stream(split).filter(StrUtil::isNotBlank).forEach(result::add);
        return result;
    }

    @Override
    @SneakyThrows(Exception.class)
    public ApiRespVO rxssReadAndExport(MultipartFile zyrzFile, MultipartFile rxssFile, MultipartFile gjssFile) {
        Map<String, Map<String, String>> allZyrzDataMap = getAllZyrzDataMap(zyrzFile);

        // 乳腺手术
        List<RxssDTO> rxssList = new ArrayList<>();
        EasyExcel.read(rxssFile.getInputStream(), RxssDTO.class, new ReadListener<RxssDTO>() {
            public static final int BATCH_COUNT = 100;
            private List<RxssDTO> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

            @Override
            public void invoke(RxssDTO data, AnalysisContext context) {
                this.cachedDataList.add(data);
                if (this.cachedDataList.size() >= BATCH_COUNT) {
                    this.handleData();
                    this.cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                }
            }

            private void handleData() {
                if (CollUtil.isEmpty(this.cachedDataList)) {
                    return;
                }
                log.info("本批次共{}条数据，开始过滤！", this.cachedDataList.size());
                List<RxssDTO> filteredList = this.cachedDataList
                        .stream()
                        .filter(i -> "女".equals(i.getSex())
                                && "35".compareTo(i.getAge()) <= 0 && "64".compareTo(i.getAge()) >= 0)
                        .collect(Collectors.toList());
                log.info("过滤后还剩{}条数据！", filteredList.size());

                for (RxssDTO item : filteredList) {
                    String id = item.getId();
                    RxssDTO rxssDTO = new RxssDTO();
                    BeanUtil.copyProperties(item, rxssDTO);
                    Map<String, String> idCardAndPhoneMap = allZyrzDataMap.get(id);
                    if (MapUtil.isEmpty(idCardAndPhoneMap)) {
                        rxssList.add(rxssDTO);
                        continue;
                    }
                    rxssDTO.setIdCard(idCardAndPhoneMap.get("idCard"));
                    rxssDTO.setPhone(idCardAndPhoneMap.get("phone"));
                    rxssList.add(rxssDTO);
                }
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                this.handleData();
                log.info("共处理了{}条数据！接下析来开始导出", rxssList.size());
                // 导出
                String originalFilename = rxssFile.getOriginalFilename();
                String fileName = writeRootDirectory + FileUtil.getPrefix(originalFilename) + "(处理后).xlsx";
                EasyExcel.write(fileName, RxssDTO.class).sheet("Sheet1").doWrite(rxssList);
                log.info("导出完成！");
            }
        }).sheet().headRowNumber(2).doRead();

        // 宫颈手术
        List<RxssDTO> gjssList = new ArrayList<>();
        EasyExcel.read(gjssFile.getInputStream(), RxssDTO.class, new ReadListener<RxssDTO>() {
            public static final int BATCH_COUNT = 100;
            private List<RxssDTO> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

            @Override
            public void invoke(RxssDTO data, AnalysisContext context) {
                this.cachedDataList.add(data);
                if (this.cachedDataList.size() >= BATCH_COUNT) {
                    this.handleData();
                    this.cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                }
            }

            private void handleData() {
                if (CollUtil.isEmpty(this.cachedDataList)) {
                    return;
                }
                log.info("本批次共{}条数据，开始过滤！", this.cachedDataList.size());
                List<RxssDTO> filteredList = this.cachedDataList
                        .stream()
                        .filter(i -> "女".equals(i.getSex())
                                && "35".compareTo(i.getAge()) <= 0 && "64".compareTo(i.getAge()) >= 0)
                        .collect(Collectors.toList());
                log.info("过滤后还剩{}条数据！", filteredList.size());

                for (RxssDTO item : filteredList) {
                    String id = item.getId();
                    RxssDTO gjssDTO = new RxssDTO();
                    BeanUtil.copyProperties(item, gjssDTO);
                    Map<String, String> idCardAndPhoneMap = allZyrzDataMap.get(id);
                    if (MapUtil.isEmpty(idCardAndPhoneMap)) {
                        gjssList.add(gjssDTO);
                        continue;
                    }
                    gjssDTO.setIdCard(idCardAndPhoneMap.get("idCard"));
                    gjssDTO.setPhone(idCardAndPhoneMap.get("phone"));
                    gjssList.add(gjssDTO);
                }
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                this.handleData();
                log.info("共处理了{}条数据！接下析来开始导出", gjssList.size());
                // 导出
                String originalFilename = gjssFile.getOriginalFilename();
                String fileName = writeRootDirectory + FileUtil.getPrefix(originalFilename) + "(处理后).xlsx";
                EasyExcel.write(fileName, RxssDTO.class).sheet("Sheet1").doWrite(gjssList);
                log.info("导出完成！");
            }
        }).sheet().headRowNumber(1).doRead();
        String rxssPath = "文件生成路径：" + writeRootDirectory + FileUtil.getPrefix(rxssFile.getOriginalFilename()) + "(处理后).xlsx";
        String gjssPath = "文件生成路径：" + writeRootDirectory + FileUtil.getPrefix(gjssFile.getOriginalFilename()) + "(处理后).xlsx";
        return new ApiRespVO("200", Arrays.asList(rxssPath, gjssPath));
    }

    private static Map<String, Map<String, String>> getAllZyrzDataMap(MultipartFile zyrzFile) throws IOException {
        Map<String, Map<String, String>> allZyrzDataMap = new HashMap<>(16);
        EasyExcel.read(zyrzFile.getInputStream(), ZyrzDTO.class, new ReadListener<ZyrzDTO>() {
                    public static final int BATCH_COUNT = 100;
                    private List<ZyrzDTO> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

                    @Override
                    public void invoke(ZyrzDTO data, AnalysisContext context) {
                        this.cachedDataList.add(data);
                        if (this.cachedDataList.size() >= BATCH_COUNT) {
                            this.handleData();
                            this.cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                        }
                    }

                    private void handleData() {
                        if (CollUtil.isEmpty(this.cachedDataList)) {
                            return;
                        }
                        this.cachedDataList.forEach(i -> {
                            Map<String, String> zyrzData = new HashMap<>(2);
                            zyrzData.put("idCard", i.getIdCard());
                            zyrzData.put("phone", i.getPhone());
                            allZyrzDataMap.put(i.getCaseNumber(), zyrzData);
                        });
                    }

                    @Override
                    public void doAfterAllAnalysed(AnalysisContext context) {
                        this.handleData();
                    }
                })
                .sheet()
                .headRowNumber(5)
                .doRead();
        return allZyrzDataMap;
    }

    private static final List<String> CLASSIFICATIONS = Arrays.asList(
            "ASC-US",
            "重度炎症",
            "中度炎症",
            "轻度炎症",
            "细菌性阴道病",
            "未见上皮内病变或恶性病变"
    );

    @Override
    @SneakyThrows(Exception.class)
    public ApiRespVO tctAndHpvReadAndExport(MultipartFile mzrzFile, MultipartFile tctFile, MultipartFile hpvFile) {
        Map<String, Map<String, String>> allMzrzDataMap = getAllMzrzDataMap(mzrzFile);
        // tct
        List<TctDTO> tctList = new ArrayList<>();
        EasyExcel.read(tctFile.getInputStream(), TctDTO.class, new ReadListener<TctDTO>() {

            public static final int BATCH_COUNT = 100;
            private List<TctDTO> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

            @Override
            public void invoke(TctDTO data, AnalysisContext context) {
                this.cachedDataList.add(data);
                if (this.cachedDataList.size() >= BATCH_COUNT) {
                    // 处理业务逻辑
                    this.handleData();
                    // 存储完成清理 list
                    this.cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                }
            }

            private void handleData() {
                if (CollUtil.isEmpty(this.cachedDataList)) {
                    return;
                }
                log.info("本批次共{}条数据，开始过滤！", this.cachedDataList.size());
                List<TctDTO> filteredList = this.cachedDataList
                        .stream()
                        .filter(i -> "女".equals(i.getSex())
                                && "35".compareTo(i.getAge()) <= 0 && "64".compareTo(i.getAge()) >= 0)
                        .collect(Collectors.toList());
                log.info("过滤后还剩{}条数据！", filteredList.size());

                for (TctDTO item : filteredList) {
                    String expertOpinion = item.getExpertOpinion();
                    if (StrUtil.isBlank(expertOpinion)) {
                        tctList.add(item);
                        continue;
                    }
                    Optional<String> foundUpperCate = CLASSIFICATIONS
                            .stream()
                            .filter(expertOpinion::contains)
                            .reduce((first, second) -> second);
                    List<String> lowerCates = CATEGORIES
                            .stream()
                            .map(String::toLowerCase)
                            .collect(Collectors.toList());
                    Optional<String> foundLowerCate = lowerCates
                            .stream()
                            .filter(expertOpinion::contains)
                            .reduce((first, second) -> second);

                    String filteredCate = foundUpperCate.orElse(foundLowerCate.orElse(expertOpinion));
                    TctDTO tctDTO = new TctDTO();
                    BeanUtil.copyProperties(item, tctDTO);
                    tctDTO.setExpertOpinionType(filteredCate);
                    // 2025/9/4 15:57:44设置诊断时间格式是yyyy.mm.dd
                    String diagnosisDate = tctDTO.getDiagnosisDate();
                    if (StrUtil.isNotBlank(diagnosisDate)) {
                        String datePart = diagnosisDate.substring(0, diagnosisDate.indexOf(" "));
                        String formattedDate = datePart.replace("/", ".");
                        tctDTO.setDiagnosisDate(formattedDate);
                    }

                    String age = item.getAge();
                    String department = item.getDepartment();
                    String id = item.getName() + StrUtil.COLON +
                            (StrUtil.isNotBlank(age) ? (age.contains("岁") ? age : age + "岁") : "") + StrUtil.COLON +
                            (StrUtil.isNotBlank(department) ? ("妇科".equals(department) ? "妇科门诊" : department) : "");
                    Map<String, String> idCardAndPhoneMap = allMzrzDataMap.get(id);
                    if (MapUtil.isNotEmpty(idCardAndPhoneMap)) {
                        tctDTO.setIdCard(idCardAndPhoneMap.get("idCard"));
                        tctDTO.setPhone(idCardAndPhoneMap.get("phone"));
                    }
                    tctList.add(tctDTO);
                }
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                this.handleData();
                log.info("共处理了{}条数据！接下析来开始导出", tctList.size());
                // 导出
                String filename = tctFile.getOriginalFilename();
                String fileName = writeRootDirectory + FileUtil.getPrefix(filename) + "(处理后).xlsx";
                EasyExcel.write(fileName, TctDTO.class).sheet("Sheet1").doWrite(tctList);
                log.info("导出完成！");
            }
        }).sheet().headRowNumber(1).doRead();
        // hpv
        List<HpvDTO> hpvList = new ArrayList<>();
        EasyExcel.read(hpvFile.getInputStream(), HpvDTO.class, new ReadListener<HpvDTO>() {

            public static final int BATCH_COUNT = 100;
            private List<HpvDTO> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

            @Override
            public void invoke(HpvDTO data, AnalysisContext context) {
                this.cachedDataList.add(data);
                if (this.cachedDataList.size() >= BATCH_COUNT) {
                    // 处理业务逻辑
                    this.handleData();
                    // 存储完成清理 list
                    this.cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                }
            }

            private void handleData() {
                if (CollUtil.isEmpty(this.cachedDataList)) {
                    return;
                }
                log.info("本批次共{}条数据，开始过滤！", this.cachedDataList.size());
                List<HpvDTO> filteredList = this.cachedDataList
                        .stream()
                        .filter(i -> "女".equals(i.getSex())
                                && "35".compareTo(i.getAge()) <= 0 && "64".compareTo(i.getAge()) >= 0)
                        .collect(Collectors.toList());
                log.info("过滤后还剩{}条数据！", filteredList.size());

                for (HpvDTO item : filteredList) {
                    String finalOpinion = item.getFinalOpinion();
                    HpvDTO hpvDTO = new HpvDTO();
                    BeanUtil.copyProperties(item, hpvDTO);
                    hpvDTO.setFinalOpinionType(extractNumbers(finalOpinion));
                    // 审核报告日期格式转为yyyy.mm.dd
                    String reviewDate = hpvDTO.getReviewDate();
                    if (StrUtil.isNotBlank(reviewDate)) {
                        String datePart = reviewDate.substring(0, reviewDate.indexOf(" "));
                        String formattedDate = datePart.replace("/", ".");
                        hpvDTO.setReviewDate(formattedDate);
                    }

                    String age = item.getAge();
                    String inspectionDepartment = item.getInspectionDepartment();
                    String id = item.getName() + StrUtil.COLON +
                            (StrUtil.isNotBlank(age) ? (age.contains("岁") ? age : age + "岁") : "") + StrUtil.COLON +
                            (StrUtil.isNotBlank(inspectionDepartment) ? ("妇科".equals(inspectionDepartment) ? "妇科门诊" : inspectionDepartment) : "");
                    Map<String, String> idCardAndPhoneMap = allMzrzDataMap.get(id);
                    if (MapUtil.isNotEmpty(idCardAndPhoneMap)) {
                        hpvDTO.setIdCard(idCardAndPhoneMap.get("idCard"));
                        hpvDTO.setPhone(idCardAndPhoneMap.get("phone"));
                    }
                    hpvList.add(hpvDTO);
                }
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                this.handleData();
                log.info("共处理了{}条数据！接下析来开始导出", hpvList.size());
                // 导出
                String filename = hpvFile.getOriginalFilename();
                String fileName = writeRootDirectory + FileUtil.getPrefix(filename) + "(处理后).xlsx";
                EasyExcel.write(fileName, HpvDTO.class).sheet("Sheet1").doWrite(hpvList);
                log.info("导出完成！");
            }
        }).sheet().headRowNumber(1).doRead();
        String tctPath = "文件生成路径：" + writeRootDirectory + FileUtil.getPrefix(tctFile.getOriginalFilename()) + "(处理后).xlsx";
        String hpvPath = "文件生成路径：" + writeRootDirectory + FileUtil.getPrefix(hpvFile.getOriginalFilename()) + "(处理后).xlsx";
        return new ApiRespVO("200", Arrays.asList(tctPath, hpvPath));
    }
    public static String formatLocalDate(LocalDate date) {
        if (date == null) {
            return "";
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd");
        return date.format(formatter);
    }
    @Override
    @SneakyThrows(Exception.class)
    public ApiRespVO mbglmzfyjs(MultipartFile mzrzFile, MultipartFile mbglmzFile) {
        Map<String, BigDecimal> totalCostMap = getMzTotalCostGroupByIdCard(mzrzFile);
        List<MbglmzDTO> mbglmzList = new ArrayList<>();
        EasyExcel.read(mbglmzFile.getInputStream(), MbglmzDTO.class, new ReadListener<MbglmzDTO>() {
                    public static final int BATCH_COUNT = 100;
                    private List<MbglmzDTO> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

                    @Override
                    public void invoke(MbglmzDTO data, AnalysisContext context) {
                        this.cachedDataList.add(data);
                        if (this.cachedDataList.size() >= BATCH_COUNT) {
                            this.handleData();
                            this.cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                        }
                    }

                    private void handleData() {
                        if (CollUtil.isEmpty(this.cachedDataList)) {
                            return;
                        }
                        mbglmzList.addAll(cachedDataList);
                    }

                    @Override
                    public void doAfterAllAnalysed(AnalysisContext context) {
                        this.handleData();
                        mbglmzList.forEach(i -> {
                            BigDecimal cost = totalCostMap.getOrDefault(i.getIdCard(), null);
                            i.setCost(cost);
                        });
                        log.info("共处理了{}条数据！接下析来开始导出", mbglmzList.size());
                        // 所有人的总费用
                        BigDecimal total = mbglmzList.stream()
                                .map(MbglmzDTO::getCost)
                                .filter(Objects::nonNull)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                        MbglmzDTO mbglmzDTO = new MbglmzDTO();
                        mbglmzDTO.setCost(total);
                        // 导出
                        mbglmzList.add(mbglmzDTO);
                        String filename = mbglmzFile.getOriginalFilename();
                        String fileName = writeRootDirectory + FileUtil.getPrefix(filename) + "(处理后).xlsx";
                        EasyExcel.write(fileName, MbglmzDTO.class).sheet("Sheet1").doWrite(mbglmzList);
                        log.info("导出完成！");
                    }
                })
                .sheet()
                .headRowNumber(1)
                .doRead();
        String mbglmzPath = "文件生成路径：" + writeRootDirectory + FileUtil.getPrefix(mbglmzFile.getOriginalFilename()) + "(处理后).xlsx";
        return new ApiRespVO("200", Collections.singletonList(mbglmzPath));
    }

    @Override
    @SneakyThrows(Exception.class)
    public ApiRespVO mbglzyfyjs(MultipartFile zyrzFile, MultipartFile mbglzyFile) {
        Map<String, BigDecimal> totalCostMap = getZyTotalCostGroupByIdCard(zyrzFile);
        List<MbglzyDTO> mbglzyList = new ArrayList<>();
        EasyExcel.read(mbglzyFile.getInputStream(), MbglzyDTO.class, new ReadListener<MbglzyDTO>() {
                    public static final int BATCH_COUNT = 100;
                    private List<MbglzyDTO> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

                    @Override
                    public void invoke(MbglzyDTO data, AnalysisContext context) {
                        this.cachedDataList.add(data);
                        if (this.cachedDataList.size() >= BATCH_COUNT) {
                            this.handleData();
                            this.cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                        }
                    }

                    private void handleData() {
                        if (CollUtil.isEmpty(this.cachedDataList)) {
                            return;
                        }
                        mbglzyList.addAll(cachedDataList);
                    }

                    @Override
                    public void doAfterAllAnalysed(AnalysisContext context) {
                        this.handleData();
                        mbglzyList.forEach(i -> {
                            BigDecimal cost = totalCostMap.getOrDefault(i.getIdCard(), null);
                            i.setCost(cost);
                        });
                        log.info("共处理了{}条数据！接下析来开始导出", mbglzyList.size());
                        // 所有人的总费用
                        BigDecimal total = mbglzyList.stream()
                                .map(MbglzyDTO::getCost)
                                .filter(Objects::nonNull)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                        MbglzyDTO mbglzyDTO = new MbglzyDTO();
                        mbglzyDTO.setCost(total);
                        // 导出
                        mbglzyList.add(mbglzyDTO);
                        String filename = mbglzyFile.getOriginalFilename();
                        String fileName = writeRootDirectory + FileUtil.getPrefix(filename) + "(处理后).xlsx";
                        EasyExcel.write(fileName, MbglmzDTO.class).sheet("Sheet1").doWrite(mbglzyList);
                        log.info("导出完成！");
                    }
                })
                .sheet()
                .headRowNumber(1)
                .doRead();
        String mbglzyPath = "文件生成路径：" + writeRootDirectory + FileUtil.getPrefix(mbglzyFile.getOriginalFilename()) + "(处理后).xlsx";
        return new ApiRespVO("200", Collections.singletonList(mbglzyPath));
    }

    private static Map<String, BigDecimal> getMzTotalCostGroupByIdCard(MultipartFile mzrzFile) throws IOException {
        final Map<String, BigDecimal>[] totalCostMap = new Map[]{new HashMap<>(16)};
        List<MzrzDTO> mzrzList = new ArrayList<>();
        EasyExcel.read(mzrzFile.getInputStream(), MzrzDTO.class, new ReadListener<MzrzDTO>() {
                    public static final int BATCH_COUNT = 100;
                    private List<MzrzDTO> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

                    @Override
                    public void invoke(MzrzDTO data, AnalysisContext context) {
                        this.cachedDataList.add(data);
                        if (this.cachedDataList.size() >= BATCH_COUNT) {
                            this.handleData();
                            this.cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                        }
                    }

                    private void handleData() {
                        if (CollUtil.isEmpty(this.cachedDataList)) {
                            return;
                        }
                        mzrzList.addAll(cachedDataList);
                    }

                    @Override
                    public void doAfterAllAnalysed(AnalysisContext context) {
                        this.handleData();
                        totalCostMap[0] = mzrzList.stream()
                                .filter(i -> StrUtil.isNotBlank(i.getIdCard()))
                                .collect(Collectors.groupingBy(MzrzDTO::getIdCard,
                                        Collectors.reducing(BigDecimal.ZERO, // 初始值
                                                MzrzDTO::getTotalCost, // 提取 totalCost
                                                BigDecimal::add // 求和
                                        )));
                    }
                })
                .sheet()
                .headRowNumber(5)
                .doRead();
        return totalCostMap[0];
    }

    private static Map<String, BigDecimal> getZyTotalCostGroupByIdCard(MultipartFile zyrzFile) throws IOException {
        final Map<String, BigDecimal>[] totalCostMap = new Map[]{new HashMap<>(16)};
        List<ZyrzDTO> zyrzList = new ArrayList<>();
        EasyExcel.read(zyrzFile.getInputStream(), ZyrzDTO.class, new ReadListener<ZyrzDTO>() {
                    public static final int BATCH_COUNT = 100;
                    private List<ZyrzDTO> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

                    @Override
                    public void invoke(ZyrzDTO data, AnalysisContext context) {
                        this.cachedDataList.add(data);
                        if (this.cachedDataList.size() >= BATCH_COUNT) {
                            this.handleData();
                            this.cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                        }
                    }

                    private void handleData() {
                        if (CollUtil.isEmpty(this.cachedDataList)) {
                            return;
                        }
                        zyrzList.addAll(cachedDataList);
                    }

                    @Override
                    public void doAfterAllAnalysed(AnalysisContext context) {
                        this.handleData();
                        totalCostMap[0] = zyrzList.stream()
                                .filter(i -> StrUtil.isNotBlank(i.getIdCard()))
                                .collect(Collectors.groupingBy(ZyrzDTO::getIdCard,
                                        Collectors.reducing(BigDecimal.ZERO, // 初始值
                                                ZyrzDTO::getTotalCost, // 提取 totalCost
                                                BigDecimal::add // 求和
                                        )));
                    }
                })
                .sheet()
                .headRowNumber(5)
                .doRead();
        return totalCostMap[0];
    }

    private static Map<String, Map<String, String>> getAllMzrzDataMap(MultipartFile mzrzFile) throws IOException {
        Map<String, Map<String, String>> allMzrzDataMap = new HashMap<>(16);
        EasyExcel.read(mzrzFile.getInputStream(), MzrzDTO.class, new ReadListener<MzrzDTO>() {
                    public static final int BATCH_COUNT = 100;
                    private List<MzrzDTO> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

                    @Override
                    public void invoke(MzrzDTO data, AnalysisContext context) {
                        this.cachedDataList.add(data);
                        if (this.cachedDataList.size() >= BATCH_COUNT) {
                            this.handleData();
                            this.cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                        }
                    }

                    private void handleData() {
                        if (CollUtil.isEmpty(this.cachedDataList)) {
                            return;
                        }
                        this.cachedDataList.forEach(i -> {
                            Map<String, String> zyrzData = new HashMap<>(2);
                            String mzrzKey = i.getName() + StrUtil.COLON + i.getAge() + StrUtil.COLON + i.getDept();
                            zyrzData.put("idCard", i.getIdCard());
                            zyrzData.put("phone", i.getPhone());
                            allMzrzDataMap.put(mzrzKey, zyrzData);
                        });
                    }

                    @Override
                    public void doAfterAllAnalysed(AnalysisContext context) {
                        this.handleData();
                    }
                })
                .sheet()
                .headRowNumber(5)
                .doRead();
        return allMzrzDataMap;
    }

    private static final List<String> HPV_TYPES = Arrays.asList(
            "16", "18", "31", "33", "35", "39", "45", "51", "52", "56", "58", "59", "66", "68"
    );

    private static String extractNumbers(String opinion) {
        if (StrUtil.isBlank(opinion)) {
            return "阴性";
        }
        // 创建一个正则表达式，用于匹配目标数字
        String regex = String.join("|", HPV_TYPES);
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(opinion);

        List<String> foundNumbers = new ArrayList<>();
        while (matcher.find()) {
            foundNumbers.add(matcher.group());
        }
        if (CollUtil.isNotEmpty(foundNumbers)) {
            return String.join(",", foundNumbers);
        }
        if (opinion.contains("低危型：阴性高危型：阴性")) {
            return "阴性";
        }
        return "阴性";
    }


}
